package com.liuwa.social.weixin.weapp.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.liuwa.common.core.redis.RedisCache;
import com.liuwa.common.utils.spring.SpringUtils;
import com.liuwa.social.config.SocialProperties;
import com.liuwa.social.http.WeixinHttpClient;
import com.liuwa.social.weixin.weapp.model.WeappData;
import com.liuwa.social.weixin.weapp.model.WeappPhoneInfo;
import com.liuwa.social.weixin.weapp.model.WeappSession;
import com.liuwa.social.weixin.weapp.model.WeappUserInfo;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.util.concurrent.TimeUnit;

/**
 * 小程序工具
 * @author rubekid
 *
 * 2017年1月9日 下午4:03:31
 */
public class WeappUtil {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(WeappUtil.class);
	
	/**
	 * 小程序 appid
	 */
	public static final String APP_ID = SocialProperties.getProperty("social.weapp.app_id");

	/**
	 * 小程序 secret
	 */
	public static final String APP_SECRET = SocialProperties.getProperty("social.weapp.app_secret");

	/**
	 * 获取session 
	 */
	public static final String SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";

	/**
	 * session 缓存
	 */
	public static final String SESSION_CACHE_KEY_PREFIX = "weapp:session:";

	private static RedisCache redisCache = SpringUtils.getBean(RedisCache.class);

	
	/**
	 * 获取session
	 * @param code
	 * @return
	 */
	public static WeappSession getSessionByCode(String code){
		return getSessionByCode(APP_ID, APP_SECRET, code);
	}
	
	/**
	 * 获取session
	 * @param code
	 * @return
	 */
	public static WeappSession getSessionByCode(String appId, String appSecret, String code){
		String sessionId = code + "@" + appId;
		WeappSession session = getSessionById(sessionId);
		if(session == null || session.getOpenid() == null){
			String url = String.format(SESSION_URL, appId, appSecret, code);
			session =  WeixinHttpClient.getForObject(url, WeappSession.class);
			if(session != null && session.getOpenid() != null){
				session.setSessionId(sessionId);
				create3rdSession(session);
			}
			else{
				LOGGER.error("获取Session 失败 : {}" , JSON.toJSONString(session));
			}
		}


		return session;
	}
	
	/**
	 * 根据sessionId 获取session
	 * @param sessionId
	 * @return
	 */
	public static WeappSession getSessionById(String sessionId){
		String key = sessionKey(sessionId);
		return redisCache.getCacheObject(key);
	}
	
	
	/**
	 * 生成sessionID
	 * @param session
	 */
	public static void create3rdSession(WeappSession session){
		String sessionId = session.getSessionId() != null ? session.getSessionId() : RandomStringUtils.randomAlphanumeric(64);
		if(session != null){
			session.setSessionId(sessionId);
			String key = sessionKey(sessionId);
			redisCache.setCacheObject(key, session, session.getExpiresIn(), TimeUnit.SECONDS);
		}
	}
	
	/**
	 * 获取微信用户信息
	 * @param userData
	 * @param sessionKey
	 * @return
	 */
	public static WeappUserInfo getUserInfo(WeappData userData, String sessionKey){
		return getUserInfo(APP_ID, userData, sessionKey);
	}

	/**
	 * 获取微信用户信息
	 * @param appId
	 * @param userData
	 * @param sessionKey
	 * @return
	 */
	public static WeappUserInfo getUserInfo(String appId, WeappData userData, String sessionKey){
		try{
			AES aes = new AES();
	        byte[] resultByte = aes.decrypt(Base64.decodeBase64(userData.getEncryptedData()),
	        		Base64.decodeBase64(sessionKey), Base64.decodeBase64(userData.getIv()));
	        if(null != resultByte && resultByte.length > 0){
	            String userInfo = new String(resultByte, "UTF-8");
	            WeappUserInfo userInfoVo = JSONObject.parseObject(userInfo, WeappUserInfo.class);
	            if(userInfoVo.getWatermark().getAppid().equals(appId)){
	            	return userInfoVo;
	            }
	        }
		}
		catch(InvalidAlgorithmParameterException | UnsupportedEncodingException ex){
			LOGGER.error(ex.getMessage(), ex);
		}
		return null;
	}

	/**
	 * 获取手机信息
	 * @param phoneData
	 * @param sessionKey
	 * @return
	 */
	public static WeappPhoneInfo getPhoneInfo(WeappData phoneData, String sessionKey){
		return  decrypt(phoneData, sessionKey, WeappPhoneInfo.class);
	}

	/**
	 * 数据解析
	 * @param weappData
	 * @param sessionKey
	 * @param clazz
	 * @param <T>
	 * @return
	 */
	public static <T> T decrypt(WeappData weappData, String sessionKey, Class<T> clazz){
		JSONObject json = decrypt(weappData, sessionKey);
		if(json != null){
			return JSONObject.parseObject(json.toString(), clazz);
		}
		return null;
	}

	/**
	 * 数据解析
	 * @param weappData
	 * @param sessionKey
	 * @return
	 */
	public static JSONObject decrypt(WeappData weappData, String sessionKey){
		try {
			AES aes = new AES();
			byte[] resultByte = aes.decrypt(Base64.decodeBase64(weappData.getEncryptedData()), Base64.decodeBase64(sessionKey), Base64.decodeBase64(weappData.getIv()));
			if(null != resultByte && resultByte.length > 0){
				String str = new String(resultByte, "UTF-8");
				return JSONObject.parseObject(str);
			}
		} catch (InvalidAlgorithmParameterException e) {
			LOGGER.error(e.getMessage() ,e);
		} catch (UnsupportedEncodingException e) {
			LOGGER.error(e.getMessage() ,e);
		}
		return null;
	}

	/**
	 * session 缓存key
	 * @param sessionId
	 * @return
	 */
	private static String sessionKey(String sessionId){
		return SESSION_CACHE_KEY_PREFIX + sessionId;
	}

}
